let currentToken = null;
let currentAttribute = null;

let stack = [{type: "document", children: []}];


function emit(token) {
    if(token.type == "text"){
        console.log("week02 dom tree emit token.type is text ");
        return;
    }
    let top = stack[stack.length - 1];
    if(token.type == "startTag") {
        console.log("week02 dom tree deal startTag");

        let element = {
            type: "element",
            children: [],
            attributes: []
        };
        

        element.tagName = token.tagName;

        for(let p in token) {
            if(p != "type" && p != "tagName") {
                // 获取节点 的 name 和 value
                element.attributes.push({
                    name: p,
                    value: token[p]
                });
            }
        }

        top.children.push(element);
        element.parent = top;

        if(!token.isSelfClosing) {
            stack.push(element);
        }

        currentTextNode = null;


    } else if(token.type == "endTag") {
        console.log("week02 dom tree deal endTag");
        if(top.tagName != token.tagName) {
            console.log("week02 dom tree top.tagName:" + top.tagName + " token.tagName:" + token.tagName);
            throw new Error("Tag start end doesn't math");
        } else {
            stack.pop();
        }
        currentTextNode = null;
    }

}

const EOF = Symbol("EOF");

// emit 测试
emit({type: "text"});
emit({type: "startTag"});
emit({type: "endTag"});


function data(unit) {
    console.log("week02 dom tree data:" + data);
    if(unit == "<") {
        return tagOpen;
    } else if(unit == EOF) {
        emit({
            type: "EOF"
        });
        return ;
    } else {
        emit({
            type: "text",
            content: unit
        });
        return data;
    }
}

function tagOpen(unit) {
    if(unit == "/") {
        return endTagOpen;
    } else if(unit.match(/^[a-zA-Z]$/)) {
        currentToken = {
            type: "startTag",
            tagName: ""
        }
        return tagName(unit);
    } else {
        emit({
            type: "text",
            content: unit
        });
        return ;

    }
}

function tagName(unit) {
    if(unit.match(/^[\t\n\f ]$/)) {
        return beforeAttributeName;
    } else if(unit == "/") {
        return selfClosingStartTag;
    } else if(unit.match(/^[A-Z]$/)) {
        currentToken.tagName += unit; 
        return tagName;
    } else if(unit == ">") {
        emit(currentToken);
        return data;
    } else {
        currentToken.tagName += unit;
        return tagName;
    }

}

function beforeAttributeName(unit) {
    if(unit.match(/^[\t\n\f ]$/)) {
        return beforeAttributeName;
    } else if(unit == "/" || unit == ">" || unit == "EOF") {
        return afterAttributeName(unit);
    } else if(unit == "=") {
        console.log("week02 dom tree beforeAttributeName unit:" + unit);
    } else {
        currentAttribute = {
            name: "",
            value: ""
        }
        return attributeName(unit);
    }
}


function attributeName(unit) {
    if(unit.match(/^[\t\n\f ]$/) || unit == "/" || unit == ">" || unit == "EOF") {
        return afterAttributeName(unit);
    } else if(unit == "=") {
        return beforeAttributeValue;
    } else if(unit == "\u0000") {
        console.log("week02 dom tree attributeName: \u0000");
    } else if(unit == "\"" || unit == "'" || unit == "<") {
        console.log("week02 dom tree attributeName unit:" + unit);
    } else {
        currentAttribute.name += unit;
        return attributeName;
    }
}

function beforeAttributeValue(unit) {
    if(unit.match(/^[\t\n\f ]$/) || unit == "/" || unit == ">" || unit == EOF) {
        return beforeAttributeValue;
    } else if(unit == "\"") {
        return doubleQuotedAttributeValue;
    } else if(unit == "\'") {
        return singleQuotedAttributeValue;
    } else if(unit == ">") {
        console.log("week02 dom tree beforeAttributeValue > ");
    } else {
        return UnquotedAttributeValue(unit);
    }
}


function doubleQuotedAttributeValue(unit) {
    if(unit == "\"") {
        currentToken[currentAttribute.name] = currentAttribute.value;
        return afterQuotedAttributeValue;
    } else if(unit == "\u0000") {
        console.log("week02 dom tree doubleQuotedAttributeValue \u0000 ");
    } else if(unit == EOF) {
        console.log("week02 dom tree doubleQuotedAttributeValue EOF ");
    } else {
        currentAttribute.value += unit;
        return doubleQuotedAttributeValue;
    }
}


function singleQuotedAttributeValue(unit) {
    if(unit == "\'") {
        currentToken[currentAttribute.name] = currentAttribute.value;
        return afterQuotedAttributeValue;
    } else if (unit == "\u0000") {
        console.log("week02 dom tree singleQuotedAttributeValue \u0000 ");
    } else if(unit == EOF) {
        console.log("week02 dom tree singleQuotedAttributeValue EOF ");
    } else {
        currentAttribute.value += unit;
        return doubleQuotedAttributeValue;
    }
}


function afterQuotedAttributeValue(unit) {
    if(unit.match(/^[\t\n\f ]$/)) {
        return beforeAttributeName;
    } else if(unit == "/") {
        return selfClosingStartTag;
    } else if(unit == ">") {
        currentToken[currentAttribute.name] = currentAttribute.value;
        emit(currentToken);
        return data;
    } else if(unit == EOF) {
        console.log("week02 dom tree afterQuotedAttributeValue EOF");
    } else {
        currentAttribute.value += unit;
        return doubleQuotedAttributeValue;
    }
}

function UnquotedAttributeValue(unit) {
    if(unit.match(/^[\t\n\f ]$/)) {
        currentToken[currentAttribute.name] = currentAttribute.value;
        return beforeAttributeName;
    } else if(unit == "/") {
        currentToken[currentAttribute.name] = currentAttribute.value;
        return selfClosingStartTag;
    } else if(unit == ">") {
        currentToken[currentAttribute.name] = currentAttribute.value;
        emit(currentToken);
        return data;
    } else if(unit == "\u0000") {
        console.log("week02 dom tree UnquotedAttributeValue \u0000 ");
    } else if(unit == "\"" || unit == "'" || unit == "<" || unit == "=" || unit == "`"  ) {
        console.log("week02 dom tree UnquotedAttributeValue unit:" + unit);
    } else if(unit == EOF) {
        console.log("week02 dom tree EOF ");
    } else {
        currentAttribute.value += unit;
        return UnquotedAttributeValue;
    }
}

function selfClosingStartTag(unit) {
    if(unit == ">") {
        currentToken.isSelfClosing = true;
        emit(currentToken);
        return data;
    } else if(unit == "EOF") {
        console.log("week02 dom tree selfClosingStartTag ");

    } else {
        console.log("week02 dom tree selfClosingStartTag unit:" + unit);
    }
}

function endTagOpen(unit) {
    if(unit == ">") {
        currentToken.isSelfClosing = true;
        emit(currentToken);
        return data;
    } else if(unit == "EOF") {
        console.log("week02 dom tree endTagOpen ");
    } else {
        console.log("week02 dom tree endTagOpen unit:" + unit);
    }
}

function afterAttributeName(unit) {
    if(unit.match(/^[a-zA-Z]$/)) {
        currentToken = {
            type: "endTag",
            tagName: ""
        }
        return tagName(unit);
    } else if(unit == ">") {
        console.log("week02 dom tree afterAttributeName ");
    } else if(unit == EOF) {
        console.log("week02 dom tree afterAttributeName EOF ");
    } else {
        console.log("week02 dom tree afterAttributeName unit:" + unit);
    }

}

function parseHTML(html) {
    let state = data;
    for(let unit of html) {
        state = state(unit);
    }
    state = state(EOF);
    console.log("week02 dom tree stack[0] is:" + stack[0]);
}

// module.exports.parseHTML = parseHTML;

// let html1 = "EOF";
// let html1 = "/";
// let html1 = "<html>";
let html1 = "<html></html>";
parseHTML(html1);

